package com.sk.server.level1;


import com.sk.common.level1.MethodParamRpc;
import com.sk.common.level1.ObjectUtil;
import com.sk.common.level1.rpcInterface.RpcAnno;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;




/**
 * description：服务自动暴露
 *
 * @author 孙文斌
 * @Date: 2021/1/27 13:32
 */
@Slf4j

@Component
public class RpcServerExplore{

    @Autowired
    private ApplicationContext applicationContext;
    private final ConcurrentHashMap map = new ConcurrentHashMap();
    /*
     * description：auto explore server ,explore way like feign,scanning {@link RpcAnno} annotation
     * @param []
     * @return void
     **/
    @PostConstruct
    protected void register() {
        //获取带有RpcAnno注解的接口的实现类
        //todo:【优化】直接获取带有RpcAnno注解的接口(发现实现类自动继承了接口的注解，这样能找到)
        Map<String, Object> beansWithAnnotationMap = this.applicationContext.getBeansWithAnnotation(RpcAnno.class);
        //进行注册到集合中
        Class<? extends Object> clazz = null;
        for(Map.Entry<String, Object> entry : beansWithAnnotationMap.entrySet()){
            Object object = entry.getValue();//获取到实例对象的class信息
            Class<?>[] interfaces = entry.getValue().getClass().getInterfaces();
            //防止用户在类上加RpcAnno注解
            if(interfaces!=null){
                for (Class<?> anInterface : interfaces) {
                    RpcAnno annotation = anInterface.getAnnotation(RpcAnno.class);
                    if(annotation!=null){
                        //检查二义性(每个带有RpcAnno注解的接口只能有一个实现类，不然通过接口全路径调用的时候，会出现二义性)
                        if(this.map.get(anInterface.getName())!=null){
                            throw new RuntimeException("Expected only one implementation class per provider interface, but found multiple,interfaces info :"+anInterface.getName());
                        }
                        this.map.put(anInterface.getName(),entry.getValue());
                    }
                }
            }
        }
    }

    //服务的调用（反射的方式）
    public Object invoke(MethodParamRpc methodParam) {
        try {
            //检查服务是否暴露
            ObjectUtil.checkNotNull(methodParam.getClassName(), "className is null");
            ObjectUtil.checkNotNull(methodParam.getMethodName(), "methodName is null");
            Object object = ObjectUtil.checkNotNull(map.get(methodParam.getClassName()), "No corresponding execution class was found：" + methodParam.getClassName());
            Method method = object.getClass().getMethod(methodParam.getMethodName(), methodParam.getParameterTypes());
            ObjectUtil.checkNotNull(method, "No corresponding execution method was found：" + methodParam.getMethodName());
            return method.invoke(object,methodParam.getArguments());
        } catch (Exception e) {
            log.error("server invoke error,info:" + e);
        }
        return null;
    }

}
